package net.spatula.tally_ho.utils.html;

/* Copyright 2006 Nicklas R Johnson
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 
 * 
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 * See the License for the specific language governing permissions and 
 * limitations under the License.
 */

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
import java.util.regex.Pattern;


import org.w3c.tidy.Tidy;

public class HtmlCleaner {

	private static final String tidyStart = "<body>\n";

	private static final String tidyEnd = "\n</body>";

	private static final Pattern brbrToNewlinesPattern = Pattern.compile(
			"(<br(>|\\s*/>|\\s+[^>]*>)(\\s|&#160;|&nbsp;)*){2,}",
			Pattern.DOTALL | Pattern.CASE_INSENSITIVE);

	private static final Pattern brbrClosePattern = Pattern.compile(
			"(<br(>|\\s*/>|\\s+[^>]*>)(\\s|&#160;|&nbsp;)*){2,}",
			Pattern.DOTALL | Pattern.CASE_INSENSITIVE);

	private static final Pattern stripLeadingSpacePattern = Pattern.compile(
			"^[\\s\\r\\n]*", Pattern.DOTALL);

	private static final Pattern stripTrailingSpacePattern = Pattern.compile(
			"[\\s\\r\\n]*$", Pattern.DOTALL);

	private static final Pattern matchBlankLinesPattern = Pattern.compile(
			"[\r\n]{2,}", Pattern.DOTALL);

        
        private static final Pattern hasParagraphsPattern = Pattern.compile(
                ".*<p(>|\\s+[^>]*>).*", Pattern.DOTALL | Pattern.CASE_INSENSITIVE);

        
	private static final Pattern trimTrailingCruftPattern = Pattern
			.compile("(<br ?/?>|[\\s\\n])*$");

	private static final Pattern trimInternalCruftPattern = Pattern
			.compile("(\\n\\s*){2,}");

	public static final String clean(String text)
			throws HtmlCleanerException {

		Tidy tidy = new Tidy();

		tidy.setMakeClean(true);
		tidy.setWord2000(true);
		tidy.setLogicalEmphasis(true);
		tidy.setDocType("strict");
		tidy.setShowWarnings(false);
		tidy.setQuiet(true);
		tidy.setXHTML(true);
		tidy.setDropEmptyParas(true);

		String result = null;

		text = addParagraphs(demoronize(text));

		try {
			ByteArrayInputStream in = new ByteArrayInputStream(text
					.getBytes("UTF-8"));
			ByteArrayOutputStream out = new ByteArrayOutputStream(text.length());
			tidy.parse(in, out);
			result = out.toString("UTF-8");

		} catch (UnsupportedEncodingException e) {
			throw new HtmlCleanerException(e);
		}
		result = result.replace("\r", "");
		int startPos = result.indexOf(tidyStart) + tidyStart.length();
		int endPos = result.indexOf(tidyEnd);

		result = trimCruft(result.substring(startPos, endPos));
				
		return result;

	}

	private static String trimCruft(String string) {
		string = trimTrailingCruftPattern.matcher(string).replaceAll("");
		string = trimInternalCruftPattern.matcher(string).replaceAll("\n");
		return string;
	}

	static String demoronize(String input) {

		input = brbrToNewlinesPattern.matcher(input).replaceAll("\n\n");
		input = brbrClosePattern.matcher(input).replaceAll("");

		return input;

	}

	static String addParagraphs(String text) {
		if (hasParagraphsPattern.matcher(text).matches()) {
			return text;
		}
		StringBuffer result = new StringBuffer((int) (text.length() * 1.05));
		result.append("<p>\n");
		text = stripLeadingSpacePattern.matcher(text).replaceFirst("");
		text = stripTrailingSpacePattern.matcher(text).replaceFirst("");
		text = matchBlankLinesPattern.matcher(text).replaceAll("\n</p>\n<p>\n");
		result.append(text);
		result.append("\n</p>");

		return result.toString();

	}

	/**
	 * Convenience method to strip out unwanted tags
	 * 
	 * @param document -
	 *            the HTML to be cleaned
	 * @param tagPatterns -
	 *            a list of semicolon-separated tags with optional
	 *            comma-separated attributes specified in braces; e.g.,
	 *            "p;a{href};img{src,alt}"
	 * @see HtmlDocumentCleanser(String tagPatterns)
	 * @return
	 * @throws HtmlCleanerException 
	 */

	public static String clean(String document, String tagPatterns) throws HtmlCleanerException {
		HtmlDocumentCleanser cleanser = new HtmlDocumentCleanser(tagPatterns);
		
		document = clean(document);
		try {
			document = cleanser.cleanse(document);
		} catch (HtmlDocumentCleanserException e) {
			throw new HtmlCleanerException(e);
		}
		return document;
	}

}
